gsk: Add gsk_renderer_render_texture()
authorBenjamin Otte <otte@redhat.com>
Wed, 21 Dec 2016 19:23:46 +0000 (20:23 +0100)
committerBenjamin Otte <otte@redhat.com>
Fri, 23 Dec 2016 07:11:01 +0000 (08:11 +0100)
... and implement it for the Cairo renderer.

It's an API that instructs a renderer to render to a texture.
So far this is mostly meant to be used for testing, but I could imagine
it being useful for rendering DND icons.

docs/reference/gsk/gsk4-sections.txt
gsk/gskcairorenderer.c
gsk/gskrenderer.c
gsk/gskrenderer.h
gsk/gskrendererprivate.h

index 45b48699dd0e9a8460f8a477a5d29b32533d6e75..a67ccc19db3917f8ca2345d194576f2017a5063c 100644 (file)
@@ -12,6 +12,7 @@ gsk_renderer_unrealize
 gsk_renderer_begin_draw_frame
 gsk_renderer_end_draw_frame
 gsk_renderer_render
+gsk_renderer_render_texture
 <SUBSECTION Standard>
 GSK_IS_RENDERER
 GSK_RENDERER
index d112e4fca037a69e882ea46bbd44e29fb98303f8..af23d610f62b50dc61ee1d7b15346fb32ad0bb39 100644 (file)
@@ -45,17 +45,62 @@ gsk_cairo_renderer_unrealize (GskRenderer *renderer)
 }
 
 static void
-gsk_cairo_renderer_render (GskRenderer   *renderer,
-                           GskRenderNode *root)
+gsk_cairo_renderer_do_render (GskRenderer   *renderer,
+                              cairo_t       *cr,
+                              GskRenderNode *root)
 {
-  GskCairoRenderer *self = GSK_CAIRO_RENDERER (renderer);
-  GdkDrawingContext *context = gsk_renderer_get_drawing_context (renderer);
-  graphene_rect_t viewport;
 #ifdef G_ENABLE_DEBUG
+  GskCairoRenderer *self = GSK_CAIRO_RENDERER (renderer);
   GskProfiler *profiler;
   gint64 cpu_time;
 #endif
 
+#ifdef G_ENABLE_DEBUG
+  profiler = gsk_renderer_get_profiler (renderer);
+  gsk_profiler_timer_begin (profiler, self->profile_timers.cpu_time);
+#endif
+
+  gsk_render_node_draw (root, cr);
+
+#ifdef G_ENABLE_DEBUG
+  cpu_time = gsk_profiler_timer_end (profiler, self->profile_timers.cpu_time);
+  gsk_profiler_timer_set (profiler, self->profile_timers.cpu_time, cpu_time);
+
+  gsk_profiler_push_samples (profiler);
+#endif
+}
+
+static GskTexture *
+gsk_cairo_renderer_render_texture (GskRenderer           *renderer,
+                                   GskRenderNode         *root,
+                                   const graphene_rect_t *viewport)
+{
+  GskTexture *texture;
+  cairo_surface_t *surface;
+  cairo_t *cr;
+
+  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, ceil (viewport->size.width), ceil (viewport->size.height));
+  cr = cairo_create (surface);
+
+  cairo_translate (cr, - viewport->origin.x, - viewport->origin.y);
+
+  gsk_cairo_renderer_do_render (renderer, cr, root);
+
+  cairo_destroy (cr);
+
+  texture = gsk_texture_new_for_surface (surface);
+  cairo_surface_destroy (surface);
+
+  return texture;
+}
+
+static void
+gsk_cairo_renderer_render (GskRenderer   *renderer,
+                           GskRenderNode *root)
+{
+  GdkDrawingContext *context = gsk_renderer_get_drawing_context (renderer);
+  graphene_rect_t viewport;
+
   cairo_t *cr;
 
   cr = gdk_drawing_context_get_cairo_context (context);
@@ -78,19 +123,7 @@ gsk_cairo_renderer_render (GskRenderer   *renderer,
       cairo_restore (cr);
     }
 
-#ifdef G_ENABLE_DEBUG
-  profiler = gsk_renderer_get_profiler (renderer);
-  gsk_profiler_timer_begin (profiler, self->profile_timers.cpu_time);
-#endif
-
-  gsk_render_node_draw (root, cr);
-
-#ifdef G_ENABLE_DEBUG
-  cpu_time = gsk_profiler_timer_end (profiler, self->profile_timers.cpu_time);
-  gsk_profiler_timer_set (profiler, self->profile_timers.cpu_time, cpu_time);
-
-  gsk_profiler_push_samples (profiler);
-#endif
+  gsk_cairo_renderer_do_render (renderer, cr, root);
 }
 
 static void
@@ -101,6 +134,7 @@ gsk_cairo_renderer_class_init (GskCairoRendererClass *klass)
   renderer_class->realize = gsk_cairo_renderer_realize;
   renderer_class->unrealize = gsk_cairo_renderer_unrealize;
   renderer_class->render = gsk_cairo_renderer_render;
+  renderer_class->render_texture = gsk_cairo_renderer_render_texture;
 }
 
 static void
index b50ebd7f565b0fd2fe1ae8515a094b8e245f4db9..87a4074735ecb80a7c9e5a3241a42f9e429d9c62 100644 (file)
@@ -113,6 +113,15 @@ gsk_renderer_real_unrealize (GskRenderer *self)
   GSK_RENDERER_WARN_NOT_IMPLEMENTED_METHOD (self, unrealize);
 }
 
+static GskTexture *
+gsk_renderer_real_render_texture (GskRenderer           *self,
+                                  GskRenderNode         *root,
+                                  const graphene_rect_t *viewport)
+{
+  GSK_RENDERER_WARN_NOT_IMPLEMENTED_METHOD (self, render_texture);
+  return NULL;
+}
+
 static GdkDrawingContext *
 gsk_renderer_real_begin_draw_frame (GskRenderer          *self,
                                     const cairo_region_t *region)
@@ -259,6 +268,7 @@ gsk_renderer_class_init (GskRendererClass *klass)
   klass->begin_draw_frame = gsk_renderer_real_begin_draw_frame;
   klass->end_draw_frame = gsk_renderer_real_end_draw_frame;
   klass->render = gsk_renderer_real_render;
+  klass->render_texture = gsk_renderer_real_render_texture;
   klass->create_cairo_surface = gsk_renderer_real_create_cairo_surface;
 
   gobject_class->constructed = gsk_renderer_constructed;
@@ -606,6 +616,76 @@ gsk_renderer_unrealize (GskRenderer *renderer)
   priv->is_realized = FALSE;
 }
 
+/**
+ * gsk_renderer_render_texture:
+ * @renderer: a realized #GdkRenderer
+ * @root: a #GskRenderNode
+ * @viewport: (allow-none): the section to draw or %NULL to use @root's bounds
+ *
+ * Renders the scene graph, described by a tree of #GskRenderNode instances,
+ * to a #GskTexture.
+ *
+ * The @renderer will acquire a reference on the #GskRenderNode tree while
+ * the rendering is in progress, and will make the tree immutable.
+ *
+ * If you want to apply any transformations to @root, you should put it into a 
+ * transform node and pass that node instead.
+ *
+ * Returns: (transfer full): a #GskTexture with the rendered contents of @root.
+ *
+ * Since: 3.90
+ */
+GskTexture *
+gsk_renderer_render_texture (GskRenderer           *renderer,
+                             GskRenderNode         *root,
+                             const graphene_rect_t *viewport)
+{
+  GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
+  graphene_rect_t real_viewport;
+  GskTexture *texture;
+
+  g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL);
+  g_return_val_if_fail (priv->is_realized, NULL);
+  g_return_val_if_fail (GSK_IS_RENDER_NODE (root), NULL);
+  g_return_val_if_fail (priv->root_node == NULL, NULL);
+
+  priv->root_node = gsk_render_node_ref (root);
+  gsk_render_node_make_immutable (priv->root_node);
+
+  if (viewport == NULL)
+    {
+      gsk_render_node_get_bounds (root, &real_viewport);
+      viewport = &real_viewport;
+    }
+
+#ifdef G_ENABLE_DEBUG
+  gsk_profiler_reset (priv->profiler);
+#endif
+
+  texture = GSK_RENDERER_GET_CLASS (renderer)->render_texture (renderer, root, viewport);
+
+#ifdef G_ENABLE_DEBUG
+  if (GSK_DEBUG_CHECK (RENDERER))
+    {
+      GString *buf = g_string_new ("*** Texture stats ***\n\n");
+
+      gsk_profiler_append_counters (priv->profiler, buf);
+      g_string_append_c (buf, '\n');
+
+      gsk_profiler_append_timers (priv->profiler, buf);
+      g_string_append_c (buf, '\n');
+
+      g_print ("%s\n***\n\n", buf->str);
+
+      g_string_free (buf, TRUE);
+    }
+#endif
+
+  g_clear_pointer (&priv->root_node, gsk_render_node_unref);
+
+  return texture;
+}
+
 /**
  * gsk_renderer_render:
  * @renderer: a #GskRenderer
index 7e62c39b7115d7d3961a07a85d737a0beed04e89..0873cf76fa7b2fb94b8ea13b78a30b3863c1b0a6 100644 (file)
@@ -65,6 +65,11 @@ gboolean                gsk_renderer_realize                    (GskRenderer
 GDK_AVAILABLE_IN_3_90
 void                    gsk_renderer_unrealize                  (GskRenderer             *renderer);
 
+GDK_AVAILABLE_IN_3_90
+GskTexture *            gsk_renderer_render_texture             (GskRenderer             *renderer,
+                                                                 GskRenderNode           *root,
+                                                                 const graphene_rect_t   *viewport);
+
 GDK_AVAILABLE_IN_3_90
 GdkDrawingContext *     gsk_renderer_begin_draw_frame           (GskRenderer             *renderer,
                                                                  const cairo_region_t    *region);
index cad512782fa732eab72f216c0c52fcd824bf6ea8..d9dbe9eca0c7e8cc7baa0b29505989bf99fe13fd 100644 (file)
@@ -42,6 +42,9 @@ struct _GskRendererClass
                         GError **error);
   void (* unrealize) (GskRenderer *renderer);
 
+  GskTexture * (* render_texture) (GskRenderer           *renderer,
+                                   GskRenderNode         *root,
+                                   const graphene_rect_t *viewport);
   GdkDrawingContext * (* begin_draw_frame) (GskRenderer *renderer,
                                             const cairo_region_t *region);
   void (* end_draw_frame) (GskRenderer *renderer,